// winBiblix.cs
//
//  Copyright (C) 2007 BOUTRY Arnaud arnaud@lordphoenix.info
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation; 
// 
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
//
//

using System;
using System.Collections;
using System.IO;
using Gtk;
using Gdk;
using Mono.Unix;

namespace biblix
{
	public enum biblixaction
	{
		bxnone,
		bxadd,
		bxedit,
		bxdelete,
		bxnotedit
	}
	public partial class winBiblix : Gtk.Window
	{
		private booklist mybase;
		private biblixaction currentaction = biblixaction.bxnone;
		private book workbook,oldbook;
		private OptionList myoptionlist;
		
		//Element de construction du menu
		private ActionGroup group;
		private UIManager uim;
		private ActionEntry[] actionlist;
		const string uixml=
			"<menubar>\n"+
				"<menu name=\"mnubilibx\" action=\"actmnubiblix\"> \n"+
					"<menuitem name=\"mnuitAdd\" action=\"actAddBook\" />\n"+
					"<menuitem name=\"mnuitSave\" action=\"actSaveBook\" />\n"+
					"<menuitem name=\"mnuitUndo\" action=\"actUndo\" />\n"+
					"<menuitem name=\"mnuitDelete\" action=\"actDeleteBook\" />\n"+
					"<separator name=\"sep1\" />\n"+
				    "<menuitem name=\"mnuitopenSearch\" action=\"actOpenSearch\" />"+
			        "<separator name =\"sep2\" />\n"+
					"<menuitem name=\"mnuitQuit\" action=\"actQuit\" />\n"+
				"</menu>\n"+
				"<menu name=\"mnuAide\" action=\"actmnuAide\" > \n"+
					"<menuitem name=\"mnuitAbout\" action=\"actAbout\" />\n"+
				"</menu>\n"+
			"</menubar>\n"+
			"<toolbar name=\"maintool\" >\n"+
				"<toolitem name=\"tlbAdd\" action=\"actAddBook\" />\n"+
				"<toolitem name=\"tlbSave\" action=\"actSaveBook\" />\n"+
				"<toolitem name=\"tlbUndo\" action=\"actUndo\" />\n"+
				"<toolitem name=\"tlbDelete\" action=\"actDeleteBook\" />\n"+
				"<separator name=\"tlbsep\" />\n"+
				"<toolitem name=\"tlbQuit\" action=\"actQuit\" />\n"+
			"</toolbar>";
		const string actAddBook = "actAddBook";
		const string actSaveBook = "actSaveBook";
		const string actOpenSearch ="actOpenSearch";
		const string actUndo ="actUndo";
		const string actDeleteBook = "actDeleteBook";
		const string actQuit ="actQuit";
		const string actAbout ="actAbout";
		public winBiblix() : base(Gtk.WindowType.Toplevel)
		{
			this.Build();
			Mono.Unix.Catalog.Init("biblix","");
			//Construction barre d'outil et menu
			actionlist =  new ActionEntry[]
			{
				new ActionEntry("actmnubiblix",null,"_Biblix",null,null,null),
				new ActionEntry("actmnuAide",null,"_Aide",null,null,null),
				new ActionEntry(actAddBook,Stock.Add,"Ajouter",null,null,new EventHandler(actAddBookActivated)),
				new ActionEntry(actSaveBook,Stock.Save,"_Enregistrer",null,null,new EventHandler(actSaveBookActivated)),
				new ActionEntry(actUndo,Stock.Undo,"Annuler",null,null,new EventHandler(actUndoActivated)),
				new ActionEntry(actDeleteBook,Stock.Delete,"Supprimer",null,null,new EventHandler(actDeleteBookActivated)),
				new ActionEntry(actQuit,Stock.Quit,"_Quitter",null,null,new EventHandler(actQuitActivated)),
				new ActionEntry(actAbout,Stock.About,"A _Propos",null,null,new EventHandler(actAboutActivated)),
				new ActionEntry(actOpenSearch,Stock.Find,"_Rechercher",null,null,new EventHandler(actOpenSearchActivated))
			};
			group = new ActionGroup("MainActions");
			group.Add(actionlist);
			group.GetAction(actSaveBook).Sensitive = false;
			group.GetAction(actUndo).Sensitive = false;
			uim = new UIManager();
			uim.AddWidget += new AddWidgetHandler(OnAddWidget);
			uim.InsertActionGroup(group,0);
			uim.AddUiFromString(uixml);
			
			this.ConfigureEvent += new ConfigureEventHandler(OnConfigureEvent);
			WindowStateEvent += new WindowStateEventHandler(onWindowStateEvent);
			
			//ouverture du fichier d'option.
			string optfile = System.Environment.GetFolderPath(Environment.SpecialFolder.Personal);
			optfile+="/.config/biblix";
			if(!Directory.Exists(optfile))
				Directory.CreateDirectory(optfile);
			optfile+="/config.txt";
			if(File.Exists(optfile))
				 myoptionlist = new OptionList(optfile);
			else {
				myoptionlist = new OptionList();
				//Set optionlist values to default values
				myoptionlist.set("mainwin.maximised","0");
				myoptionlist.set("mainwin.x","0");
				myoptionlist.set("mainwin.y","0");
				myoptionlist.set("mainwin.height","");
				myoptionlist.set("mainwin.width","");
				myoptionlist.Save(optfile);
			}
			
			//Configuration en fonction des options
			if (myoptionlist.OptionValueBool("mainwin.maximised"))
				this.Maximize();
			else {
				int x = myoptionlist.OptionValueInt("mainwin.x");
				int y = myoptionlist.OptionValueInt("mainwin.y");
				this.Move(x,y);
				
				x=myoptionlist.OptionValueInt("mainwin.width");
				y=myoptionlist.OptionValueInt("mainwin.height");
				this.Resize(x,y);
			}
			
			//Ouverture fichier de base de données
			string filepath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
			filepath +="/.biblix/booklist.blix";
			mybase = new booklist(filepath);
			
			ListStore modBooklist = new ListStore(typeof(book));
			trvBooklist.AppendColumn(Catalog.GetString("Livres"),new CellRendererText(),new Gtk.TreeCellDataFunc(RenderTitle));
			trvBooklist.Model = modBooklist;
			trvBooklist.Selection.Changed += new EventHandler(SelectedBookChange);
			
			//initialisation de la liste des genres
			foreach(string genre in mybase.GetGenreList())
				cbxListGenre.AppendText(genre);
			
			//Initialisation de la liste des sources
			foreach (string source in mybase.GetSourcesList())
				cbxSource.AppendText(source);
			
			txtComment.Buffer.Changed += OnEditBook;
			txtSynopsis.Buffer.Changed += OnEditBook;
			ShowBookList(null);
		}
		
		protected void OnAddWidget(object sender,AddWidgetArgs args)
		{
			args.Widget.Show();
			mnuBox.PackStart(args.Widget,false,true,0);
		}
		
		private void RenderTitle(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			book curbook =(book)model.GetValue(iter,0);
			(cell as Gtk.CellRendererText).Markup=String.Format("{0} <i>({1})</i>", curbook.titre,curbook.auteur);
		}
		
		private void ShowBookList(ArrayList idlist)
		{
			(trvBooklist.Model as ListStore).Clear();
			ArrayList booklist = new ArrayList();
			int index=-1;
			IEnumerator i;
			if (idlist==null)
				i = mybase.getidlist().GetEnumerator();
			else 
				i = idlist.GetEnumerator();
			while(i.MoveNext())
			{
				book curbook = mybase.getbook(i.Current.ToString());
				if (curbook!=null)
				{
					if (booklist.Count>0)
					{
						IEnumerator j = booklist.GetEnumerator();
						while (j.MoveNext())
						{
							book searchbook = (book)j.Current;
							if (searchbook.serie == curbook.serie)
								index=booklist.IndexOf(searchbook)+1;
						}
					}
					if (index!=-1)
						booklist.Insert(index,curbook);
					else 
						booklist.Add(curbook);
				}
			}
			foreach(book tmpbook in booklist)
				(trvBooklist.Model as ListStore).AppendValues(tmpbook);
		}
		
		private void ShowBookDetails(book currentbook)
		{
			currentaction = biblix.biblixaction.bxnotedit;
			entAuthor.Text="";
			entTitle.Text="";
			entSerieTitle.Text="";
			entPublishYear.Text="";
			cbxListGenre.Active=-1;
			cbxNote.Active=-1;
			cbxNote.Entry.Text="";
			entVolume.Text="";
			ckbReadBook.Active=false;
			ckbPret.Active=false;
			cbxSource.Active=-1;
			txtComment.Buffer.Clear();
			txtSynopsis.Buffer.Clear();
			if (currentbook != null)
			{
				entAuthor.Text = currentbook.auteur;
				entTitle.Text = currentbook.titre;
				entSerieTitle.Text = currentbook.serie;
				cbxNote.Active = currentbook.note;
				if (currentbook.volume==0)
					entVolume.Text="";
				else
					entVolume.Text=currentbook.volume.ToString();
				ckbReadBook.Active = currentbook.lu;
				ckbPret.Active = currentbook.pret;
				txtComment.Buffer.Text = currentbook.commentaire;
				txtSynopsis.Buffer.Text = currentbook.resume;
				entPublishYear.Text = currentbook.publishyear;
				
				if (currentbook.shortdate!="01/01/0001")					
					lblDate.LabelProp = currentbook.longdate;
				else 
					lblDate.LabelProp = Catalog.GetString("Sélectionnez une date");

				int index = -1;
				if (!String.IsNullOrEmpty(currentbook.genre))
				{
					string searchgenre ="";
					ListStore listegenremodel = (ListStore)cbxListGenre.Model;
					System.Collections.IEnumerator i = listegenremodel.GetEnumerator();
					while ((i.MoveNext())&(searchgenre !=currentbook.genre))
					{
						object[] row = (System.Object[])i.Current;
						searchgenre = row[0].ToString();
						index +=1;
					}
				}
				cbxListGenre.Active = index;
				
				int indexsource = -1;
				if(!String.IsNullOrEmpty(currentbook.source))
					{
					ListStore listesourcemodel = (ListStore)cbxSource.Model;
					IEnumerator j = listesourcemodel.GetEnumerator();
					string searchsource ="";
					while ((j.MoveNext())&(searchsource != currentbook.source))
					{
						object[] row =(System.Object[])j.Current;
						searchsource = row[0].ToString();
						indexsource+=1;
					}
					}
				cbxSource.Active = indexsource;
			}
			currentaction = biblix.biblixaction.bxnone;
		}
		
		private void savebook()
		{
			switch (currentaction)
			{
				case biblix.biblixaction.bxadd:
					mybase.addbook(workbook);
					break;
				case biblix.biblixaction.bxedit :
					mybase.updatebook(workbook);
					break;
			}
			group.GetAction(actSaveBook).Sensitive = false;
			group.GetAction(actUndo).Sensitive = false;
			currentaction = biblixaction.bxnone;
		}
		
		
		//Action management methods
		protected void actAddBookActivated(object sender , EventArgs args)
		{
			if (currentaction == biblixaction.bxnone)
			{
				dlgAddBook dlg = new dlgAddBook(mybase);
				ResponseType result = (ResponseType)dlg.Run();
				if (result==ResponseType.Ok)
				{
					book newbook = dlg.newbook;
					mybase.addbook(newbook);
					this.ShowBookList(null);
				}
				dlg.Hide();
				dlg.Destroy();
				
			}
			else 
			{
				MessageDialog dlg = new MessageDialog(this,DialogFlags.DestroyWithParent,MessageType.Question,
				                                      ButtonsType.YesNo,Catalog.GetString("Des modification sont en cours voulez vous les enregistrer?"));
				if (dlg.Run()==(int)ResponseType.Yes)
				{
					savebook();
				}
				dlg.Hide();
				dlg.Destroy();
			}
		}
		
		protected void actSaveBookActivated(object sender , EventArgs args)
		{
			savebook();
			oldbook=null;
		}
		
		protected void actUndoActivated(object sender , EventArgs args)
		{
			switch (currentaction)
			{
				case biblixaction.bxedit:
					workbook = oldbook;
					ShowBookDetails(workbook);
					currentaction = biblixaction.bxnone;
					break;
				case biblixaction.bxadd:
					TreeIter iter;
					trvBooklist.Selection.GetSelected(out iter);
					(trvBooklist.Model as ListStore).Remove(ref iter);
					ShowBookDetails(null);
					workbook = null;
					break;
			}
			oldbook = null;
			group.GetAction(actSaveBook).Sensitive = false;
			group.GetAction(actUndo).Sensitive = false;
			currentaction = biblixaction.bxnone;
		}
		
		protected void actDeleteBookActivated(object sender , EventArgs args)
		{
			if (currentaction != biblixaction.bxnone)
			{
				MessageDialog dlg = new MessageDialog(this,DialogFlags.DestroyWithParent,MessageType.Warning,
				                                      ButtonsType.Close,"Attention des modifications sont en cours Enregistrez les ou annulez les avant de faire autre chose");
				dlg.Run();
				dlg.Hide();
				dlg.Destroy();
			}
			else
			{
				MessageDialog dlg = new MessageDialog(this,DialogFlags.DestroyWithParent,MessageType.Question,
				                                      ButtonsType.OkCancel,"Voulez vous vraiment supprimer le livre \"{0}\" de votre bibliothèque ?",workbook.titre);
				if ((ResponseType)dlg.Run()==ResponseType.Ok)
				{
					bool result = mybase.deletebook(workbook.id);
					if (result)
						workbook = null;
					ShowBookList(null);
					ShowBookDetails(workbook);
				}
				dlg.Hide();
				dlg.Destroy();
			}
		}
		
		protected void actQuitActivated(object sender , EventArgs args)
		{
			if(currentaction == biblixaction.bxedit)
			{
				MessageDialog dlg = new MessageDialog(this,DialogFlags.DestroyWithParent,MessageType.Question,
				                                      ButtonsType.YesNo,Catalog.GetString("Des modifications ont été effectuées voulez vous les sauvegarder avant de Quitter?"));
				ResponseType result = (ResponseType)dlg.Run();
				if (result == ResponseType.Yes)
					savebook();
				
				dlg.Hide();
				dlg.Destroy();
			}
			myoptionlist.Save();
			Application.Quit();
		}

		protected void actAboutActivated(object sender , EventArgs args)
		{
			Gtk.AboutDialog.SetUrlHook(new Gtk.AboutDialogActivateLinkFunc(openaboutlink));
			Gtk.AboutDialog about = new AboutDialog();
			about.Authors=new string[] {"BOUTRY Arnaud <arnaud@lordphoenix.info>"};
			about.Artists = new string[] {Catalog.GetString("Les icônes viennent du site : http://www.famfamfam.com")};
			about.Name="Biblix";
			about.Version = "0.2";
			about.LogoIconName="Biblix";
			about.Copyright=" (c) BOUTRY Arnaud 2007-2008"; 
			about.Website="http://biblix.lordphoenix.info";
			about.Comments=Catalog.GetString("Gérer facilement votre collection de livres");
			about.WebsiteLabel=Catalog.GetString("Site web");
            about.License=Catalog.GetString("Ce logiciel est disponible sous licence GNU/GPL V2 \n voir le fichier /usr/share/doc/biblix/COPYING");
			
			about.Run();
			about.Hide();
			about.Destroy();
		}
		
		protected void actOpenSearchActivated(object sender, EventArgs args)
		{
			winSearch searchwin = new winSearch();
			searchwin.Show();
		}
			
		
		//Component event management methods
		protected virtual void SelectedBookChange(object sender, EventArgs args)
		{
			switch (currentaction)
			{
				case biblixaction.bxedit:
					MessageDialog dlg = new MessageDialog(this,Gtk.DialogFlags.DestroyWithParent,
					                                      Gtk.MessageType.Question,Gtk.ButtonsType.YesNo,
					                                      String.Format(Catalog.GetString("Des modifications ont été apportées au livre ,{0} voulez vous les enregistrer?"),
					                                      workbook.titre));
					ResponseType result = (ResponseType)dlg.Run();
					if (result==ResponseType.Yes)
					{
						mybase.updatebook(workbook);
						group.GetAction(actSaveBook).Sensitive = false;
						group.GetAction(actUndo).Sensitive = false;
						currentaction = biblixaction.bxnone;
					}
					else 
					{
						workbook = oldbook;
						ShowBookDetails(workbook);
					    group.GetAction(actSaveBook).Sensitive = false;
						group.GetAction(actUndo).Sensitive = false;
						currentaction = biblixaction.bxnone;
					}
					dlg.Hide();
					dlg.Destroy();
					break;
				case biblixaction.bxadd :
					break;
				
				case biblixaction.bxnone:
					TreeIter selectediter;
					if (trvBooklist.Selection.GetSelected(out selectediter))
					{
						book selectedbook = (book)((trvBooklist.Model as ListStore).GetValue(selectediter,0));
						workbook = selectedbook;
						ShowBookDetails(selectedbook);
					}
					else ShowBookDetails(null);
					break;
			}
		}

		protected virtual void OnDeleteEvent (object o, Gtk.DeleteEventArgs args)
		{
			myoptionlist.Save();
			Application.Quit ();
			args.RetVal = true;
		}

		protected virtual void OnCkbFilterClicked (object sender, System.EventArgs e)
		{
			cbxFilterItem.Sensitive=ckbFilter.Active;
			cbxFilterValue.Sensitive=ckbFilter.Active;
			if (!ckbFilter.Active)
			{
				cbxFilterItem.Active=-1;
				cbxFilterValue.Active=-1;
				(cbxFilterValue.Model as ListStore).Clear();
				ShowBookList(null);
			}
		}

		protected virtual void OnEditBook (object sender, System.EventArgs e)
		{
			if(workbook != null)
			{
				if (currentaction != biblix.biblixaction.bxnotedit)
				{
					if (currentaction != biblixaction.bxadd)
						currentaction = biblix.biblixaction.bxedit;
					if (oldbook==null)
						oldbook = (book)workbook.Clone();// Ne sauvegarder que si cela n'a pas déjà été fait.
					workbook.titre = entTitle.Text;
					workbook.auteur = entAuthor.Text;
					workbook.genre = cbxListGenre.ActiveText;
					workbook.serie = entSerieTitle.Text;
					if (entVolume.Text=="")
						workbook.volume=0;
					else 
						workbook.volume = Int32.Parse(entVolume.Text);
					workbook.note=cbxNote.Active;
					workbook.lu = ckbReadBook.Active;
					workbook.source = cbxSource.ActiveText;
					workbook.pret = ckbPret.Active;
					workbook.resume = txtSynopsis.Buffer.Text;
					workbook.commentaire = txtComment.Buffer.Text;
					workbook.publishyear = entPublishYear.Text;
					group.GetAction(actSaveBook).Sensitive = true;
					group.GetAction(actUndo).Sensitive = true;
				}
			}
		}

		protected virtual void OnBtnDateClicked (object sender, System.EventArgs e)
		{
			biblix.dlgDateSelect dlgdate = new dlgDateSelect();
			dlgdate.Run();
			lblDate.LabelProp = dlgdate.SelectedDate.ToLongDateString();
			workbook.shortdate = dlgdate.SelectedDate.ToShortDateString();
			dlgdate.Hide();
			dlgdate.Destroy();
			currentaction= biblixaction.bxedit;
			group.GetAction(actSaveBook).Sensitive = true;
			group.GetAction(actUndo).Sensitive = true;
		}

		protected virtual void OnBtnAutreGenreClicked (object sender, System.EventArgs e)
		{
			biblix.dlgNewRefValue dlg = new dlgNewRefValue(Catalog.GetString("Ajout d'un genre littéraire"));
			ResponseType result = (ResponseType)dlg.Run();
			if (result==Gtk.ResponseType.Ok)
				cbxListGenre.AppendText(dlg.refvalue);
			dlg.Hide();
			dlg.Destroy();
		}

		protected virtual void OnBtnAddSourceClicked (object sender, System.EventArgs e)
		{
			biblix.dlgNewRefValue dlg = new dlgNewRefValue(Catalog.GetString("Ajout d'une source supplémentaire"));
			ResponseType result = (ResponseType)dlg.Run();
			if (result == ResponseType.Ok)
				cbxSource.AppendText(dlg.refvalue);
			dlg.Hide();
			dlg.Destroy();
		}


		protected void openaboutlink(Gtk.AboutDialog dialog, string link)
		{
			Gnome.Url.Show(link);
		}

		protected virtual void OnCbxFilterItemChanged (object sender, System.EventArgs e)
		{
			ArrayList listecritere = new ArrayList();
			(cbxFilterValue.Model as ListStore).Clear();
			switch (cbxFilterItem.Active)
			{
			case 0 :
				//Filtrage par auteur
				listecritere = mybase.GetAuthorList();
				break;
			case 1 : 
				//Filtrage par genre 
				listecritere = mybase.GetGenreList();
				break;
			case 2 :
				//Filtrage par note
				for (int i=0;i<=5;i++)
					listecritere.Add(i.ToString());
				break;
			case 3 :
				listecritere.Add(Catalog.GetString("Oui"));
				listecritere.Add(Catalog.GetString("Non"));
				break;
			}
			foreach (string critere in listecritere)
				cbxFilterValue.AppendText(critere);
		}

		protected virtual void OnCbxFilterValueChanged (object sender, System.EventArgs e)
		{
			ArrayList listid = new ArrayList();
			(trvBooklist.Model as ListStore).Clear();
			string searchvalue="";
			if (cbxFilterItem.Active==3)
			{
				if (cbxFilterValue.Active==0) searchvalue="O";
				if (cbxFilterValue.Active==1) searchvalue="N";
			}
			else
				searchvalue=cbxFilterValue.ActiveText;
			biblix.booksearchcriteria searchon=biblix.booksearchcriteria.author;
			switch (cbxFilterItem.Active)
			{
			case 0 :
				//Filtrage par auteur
				searchon = biblix.booksearchcriteria.author ;
				break;
			case 1 : 
				//Filtrage par genre 
				searchon = biblix.booksearchcriteria.genre;
				break;
			case 2 :
				//Filtrage par note
				searchon = biblix.booksearchcriteria.note;
				break;
			case 3 :
				searchon = biblix.booksearchcriteria.read;
				break;
			}
			listid = mybase.SearchBook(searchon,searchvalue);
			ShowBookList(listid);
//			foreach(string id in listid)
//			{
//				book thisbook = mybase.getbook(id); 
//				(trvBooklist.Model as ListStore).AppendValues(thisbook);
//			}
		}

		[GLib.ConnectBefore]
		protected void OnConfigureEvent (object o, Gtk.ConfigureEventArgs args)
		{
			myoptionlist.set("mainwin.x",args.Event.X.ToString());
			myoptionlist.set("mainwin.y",args.Event.Y.ToString());
			myoptionlist.set("mainwin.height",args.Event.Height.ToString());
			myoptionlist.set("mainwin.width",args.Event.Width.ToString());
//			myoptionlist.Save();
		}
		
		protected void onWindowStateEvent(object sender , WindowStateEventArgs args)
		{
			if (args.Event.NewWindowState ==WindowState.Maximized)
				myoptionlist.set("mainwin.maximised","1");
			else 
				myoptionlist.set("mainwin.maximised","0");
		}
	}
}
